package com.atguigu.gulimall.ware.listener;

import com.atguigu.common.vo.mq.OrderTo;
import com.atguigu.common.vo.mq.StockLockedTo;
import com.atguigu.gulimall.ware.service.WareSkuService;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.IOException;

/**
 * @create: 2024/9/13
 * @author: gyhe10
 * @description: 执行锁定锁定库存逆操作来解锁库存的监听器
 **/

@RabbitListener(queues = {"stock.release.stock.queue"})
@Component
public class StockReleaseListener {

    @Resource
    private WareSkuService wareSkuService;

    /**
     * 库存锁定失败，监听消息队列，解锁库存
     * @RabbitListener 用于标记类或方法，使其成为 RabbitMQ 消息的监听器，而 @RabbitHandler 则用于标记具体的处理方法
     * @param stockLockedTo
     * @param message
     */
    @RabbitHandler
    public void releaseLockedStock(StockLockedTo stockLockedTo, Message message, Channel channel) throws IOException {
        System.out.println("库存服务接收到消息，准备解锁库存...");
        try {
            wareSkuService.unlockStock(stockLockedTo);
            // 只要解锁库存方法执行成功，都需要手动 ACK，表示消息已处理成功，不需要重新入队或投递
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (Exception e) {
            // 解锁库存方法出现异常，显式地调用 basicNack 或 basicReject，并设置 requeue 参数为 true，确保消息重新入队，否则消息会一直处于 UNACKED 状态，不会立即重新投递给同一个消费者或另一个消费者
            channel.basicReject(message.getMessageProperties().getDeliveryTag(), true);
            throw new RuntimeException(e);
        }
    }

    @RabbitHandler
    public void releaseLockedStockAfterOrderClose(OrderTo orderTo, Message message, Channel channel) throws IOException {
        System.out.println("订单关闭，准备解锁库存...");
        try {
            wareSkuService.unlockStock(orderTo);
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (Exception e) {
            channel.basicReject(message.getMessageProperties().getDeliveryTag(), true);
            throw new RuntimeException(e);
        }
    }
}
